/*
将任务转移到后台线程
https://flutter.cn/docs/get-started/flutter-for/android-devs

如何将任务转移到后台线程？
在 Android 中，当你想要访问一个网络资源却又不想阻塞主线程并避免 ANR 的时候，你一般会将任务放到一个后台线程中运行。例如，你可以使用 AsyncTask、LiveData、IntentService、JobScheduler 任务或者通过 RxJava 的管道用调度器将任务切换到后台线程中。

由于 Flutter 是单线程并且运行一个事件循环（类似 Node.js），你无须担心线程的管理以及后台线程的创建。如果你在执行和 I/O 绑定的任务，例如存储访问或者网络请求，那么你可以安全地使用 async/await，并无后顾之忧。再例如，你需要执行消耗 CPU 的计算密集型工作，那么你可以将其转移到一个 Isolate 上以避免阻塞事件循环，就像你在 Android 中会将任何任务放到主线程之外一样。

对于和 I/O 绑定的任务，将方法声明为 async 方法，并在方法内 await 一个长时间运行的任务：



在 Android 中，当你继承 AsyncTask 的时候，你一般会覆写三个方法： onPreExecute()、doInBackground() 和 onPostExecute()。 Flutter 中没有对应的 API，你只需要 await 一个耗时方法调用， Dart 的事件循环就会帮你处理剩下的事情。

然而，有时候你可能需要处理大量的数据并挂起你的 UI。在 Flutter 中，可以通过使用 Isolate 来利用多核处理器的优势执行耗时或计算密集的任务。

Isolate 是独立执行的线程，不会和主执行内存堆分享内存。这意味着你无法访问主线程的变量，或者调用 setState() 更新 UI。与 Android 中线程的概念不同，isolate 如其名所示，它们无法分享内存（例如通过静态变量的形式）。

下面的例子展示了一个简单的 isolate 是如何将数据分享给主线程来更新 UI 的。

这里的 dataLoader() 就是运行在自己独立执行线程内的 Isolate
 */

import 'dart:convert';
import 'dart:isolate';
import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:http/http.dart' as http;

void main() {
  runApp(const SampleApp());
}

class SampleApp extends StatelessWidget {
  const SampleApp({super.key});

  @override
  Widget build(BuildContext context) {
    return MaterialApp(
      title: '',
      theme: ThemeData(primarySwatch: Colors.blue),
      home: const SampleAppPage(),
    );
  }
}

class SampleAppPage extends StatefulWidget {
  const SampleAppPage({super.key});

  @override
  State<StatefulWidget> createState() => _SampleAppPageState();
}

class _SampleAppPageState extends State<SampleAppPage> {
  List widgets = [];

  @override
  void initState() {
    super.initState();
    loadData();
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Sample App'),
      ),
      body: ListView.builder(
        itemCount: widgets.length,
        itemBuilder: (context, position) {
          return getRow(position);
        },
      ),
    );
  }

  Widget getRow(int i) {
    return Padding(
      padding: const EdgeInsets.all(10.0),
      child: Text("Row ${widgets[i]["title"]}"),
    );
  }

  Future<void> loadData() async {
    ReceivePort receivePort = ReceivePort();
    await Isolate.spawn(dataLoader, receivePort.sendPort);
    // The 'echo' isolate sends its SendPort as the first message.
    SendPort sendPort = await receivePort.first;

    List msg = await sendReceive(sendPort, 'https://jsonplaceholder.typicode.com/posts');
    setState(() {
      widgets = msg;
    });
  }

// The entry point for the isolate.
  static Future<void> dataLoader(SendPort sendPort) async {//注意这里前面加 static 关键字
    ReceivePort port = ReceivePort();
    sendPort.send(port.sendPort);

    await for (var msg in port) {
      String data = msg[0];
      SendPort replayTo = msg[1];

      String dataURL = data;
      http.Response response = await http.get(Uri.parse(dataURL));
      // Lots of JSON to parse
      replayTo.send(jsonDecode(response.body));
    }
  }

  Future sendReceive(SendPort port, msg) {
    ReceivePort response = ReceivePort();
    port.send([msg, response.sendPort]);
    return response.first;
  }

  //----------------------------
//   Future<void> loadData() async {
//     ReceivePort receivePort = ReceivePort();
//     await Isolate.spawn(dataLoader, receivePort.sendPort);
//
//     // The 'echo' isolate sends its SendPort as the first message.
//     SendPort sendPort = await receivePort.first;
//
//     List msg = await sendReceive(
//       sendPort,
//       'https://jsonplaceholder.typicode.com/posts',
//     );
//
//     setState(() {
//       widgets = msg;
//     });
//   }
//
// // The entry point for the isolate.
//   static Future<void> dataLoader(SendPort sendPort) async {
//     // Open the ReceivePort for incoming messages.
//     ReceivePort port = ReceivePort();
//
//     // Notify any other isolates what port this isolate listens to.
//     sendPort.send(port.sendPort);
//
//     await for (var msg in port) {
//       String data = msg[0];
//       SendPort replyTo = msg[1];
//
//       String dataURL = data;
//       http.Response response = await http.get(Uri.parse(dataURL));
//       // Lots of JSON to parse
//       replyTo.send(jsonDecode(response.body));
//     }
//   }
//
//   Future sendReceive(SendPort port, msg) {
//     ReceivePort response = ReceivePort();
//     port.send([msg, response.sendPort]);
//     return response.first;
//   }
}
